package com.godyao.mall.order.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.godyao.mall.common.utils.AssertUtils;
import com.godyao.mall.core.constants.RedisConstant;
import com.godyao.mall.core.model.OrderStatusEnum;
import com.godyao.mall.core.model.ResultMsg;
import com.godyao.mall.core.model.goods.Goods;
import com.godyao.mall.goods.api.feign.GoodsFeign;
import com.godyao.mall.order.model.Order;
import com.godyao.mall.order.model.SecKillOrder;
import com.godyao.mall.order.mq.config.DelayedRabbitMqConfig;
import com.godyao.mall.order.mq.msg.SeckillMessage;
import com.godyao.mall.order.repository.OrderRepository;
import com.godyao.mall.order.repository.SeckillOrderRepository;
import com.godyao.mall.order.service.IOrderService;
import com.godyao.mall.rabbitmq.service.ISendMsgService;
import lombok.RequiredArgsConstructor;
import org.bouncycastle.pqc.math.linearalgebra.IntUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.godyao.mall.core.constants.RedisConstant.SEC_KILL_GOODS_KEY_PREFIX;
import static com.godyao.mall.core.constants.RedisConstant.SEC_KILL_KEY_PREFIX;

/**
 * @author godyao
 * @date 2022/4/1
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements IOrderService {
    private final OrderRepository orderRepository;

    private final SeckillOrderRepository seckillOrderRepository;

    private final GoodsFeign goodsFeign;

    private final RedisTemplate redisTemplate;

    private final ISendMsgService sendMsgService;

    @Override
    public void delById(Long id) {
        orderRepository.deleteById(id);
    }

    /***
    * @author godyao
    * @description 处理超时未支付订单
    * @Param orderId
    * @return void
    * @date 2022/4/10 15:25
    */
    @Override
    public void checkOrderStatus(long orderId) {
        final Order order = orderRepository.findById(orderId).get();
        Objects.requireNonNull(order);
        if (OrderStatusEnum.PENDING_PAY.getCode() == order.getStatus()) {
            // 取消订单 回退库存
            order.setStatus(OrderStatusEnum.CANCLED.getCode());
            orderRepository.save(order);
            redisTemplate.opsForHash().increment(SEC_KILL_KEY_PREFIX + order.getGoodsId(), "stock", 1);
        }
    }

    /**
     * 消费mq消息，生成订单
     * @param seckillMessage
     */
    @Override
    //@GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public void makeOrder(SeckillMessage seckillMessage) {
        final String userId = seckillMessage.getUserId();
        final Long goodsId = seckillMessage.getGoodsId();
        // 获取商品信息
        final ResultMsg<Goods> goodsInfo = goodsFeign.findGoodsByGoodsId(goodsId);
        if (ResultMsg.isSuccess(goodsInfo) && ObjectUtil.isNotNull(goodsInfo.getData())) {
            final Goods goods = goodsInfo.getData();
            final Order order = orderRepository.save(
                    new Order()
                            .setUserId(userId)
                            .setGoodsId(goodsId)
                            .setGoodsName(goods.getGoodsName())
                            .setGoodsCount(1)
                            .setGoodsPrice(goods.getGoodsPrice())
                            .setCreateDate(Instant.now())
                            .setStatus(OrderStatusEnum.PENDING_PAY.getCode())
            );
            AssertUtils.assertTrue(ObjectUtil.isNotNull(order));
            final SecKillOrder secKillOrder = seckillOrderRepository.save(new SecKillOrder().setOrderId(order.getId())
                    .setGoodsId(goodsId)
                    .setUserId(userId));
            AssertUtils.assertTrue(ObjectUtil.isNotNull(secKillOrder));
            // 下单后的记录在redis中， 供客户端轮训查询结果 减少数据库压力和用户超买判断（这里每个用户限购一件，如果可以购买多件的话需要维护一个下单次数）
            redisTemplate.opsForValue().set(SEC_KILL_GOODS_KEY_PREFIX+userId+":"+goodsId, OrderStatusEnum.PENDING_PAY.getCode());

            // 发送消息到延迟队列中 30分钟内订单还是未支付则取消订单
            sendMsgService.sendMsg(DelayedRabbitMqConfig.DELAYED_EXCHANGE_NAME, DelayedRabbitMqConfig.DELAYED_ROUTING_KEY, order.getId().toString(), 10000);
        }
    }

    @Override
    public Order makeOrder(Order order) {
        return orderRepository.save(order);
    }

    @Override
    public Order findOrderById(Long id) {
        return orderRepository.findById(id).get();
    }

    @Override
    public Page<Order> findAll(Specification spec, Pageable pageable) {
        return orderRepository.findAll(spec, pageable);
    }
}
